import { isNaN } from 'lodash-es'

export type FormValidator = (
  value: any,
  callback: (error?: string) => void
) => void

// 正则通用验证器
export const regExpValidateHandler = (
  value: string | number,
  reg: RegExp,
  errMsg: string
) => {
  if (!reg.test(value.toString())) {
    return errMsg
  }
  return undefined
}

export const validateHandler = <T = string | number | string[] | number[]>(
  value: T,
  handler: (data: string) => string | undefined
): string | undefined => {
  if (!Array.isArray(value)) {
    return handler(((value || '') as string | number).toString())
  }
  let errMsg: string | undefined
  value.find((item, i) => {
    errMsg = handler(item, i)
    if (errMsg) {
      return true
    }
    return false
  })
  return errMsg
}

// 验证正则
export const regexpMap = {
  // ipv4地址
  ipv4: /^((1?[1-9]?\d|[1-2][0-4]\d|25[0-5])\.){3}(1?[1-9]?\d|[1-2][0-4]\d|25[0-5])$/,
  // ipv6地址
  ipv6: /(^(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))$)|(^\[(?:(?:(?:[0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(([0-9A-Fa-f]{1,4}:){0,5}:((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|(::([0-9A-Fa-f]{1,4}:){0,5}((\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b)\.){3}(\b((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\b))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))\](?::(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$)/,
  ipv4AndPort:
    /^((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.){3}(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])(?::(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$/,
  ipv6AndPort:
    /(([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4}|:)|(([0-9a-fA-F]{1,4}:){1,7}|:):([0-9a-fA-F]{1,4}:){1,6}([0-9a-fA-F]{1,4}|:)|(([0-9a-fA-F]{1,4}:){1,6}|:):([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|(([0-9a-fA-F]{1,4}:){1,5}|:):([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|(([0-9a-fA-F]{1,4}:){1,4}|:):([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|(([0-9a-fA-F]{1,4}:){1,3}|:):([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|(([0-9a-fA-F]{1,4}:){1,2}|:):[0-9a-fA-F]{1,4}:(([0-9a-fA-F]{1,4}:){1,6})|([0-9a-fA-F]{1,4}|:):(([0-9a-fA-F]{1,4}:){1,7}|:))(:\d{1,5})?$/,
  // 域名
  domain:
    // /^(?=^.{3,255}$)([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-z]{2,11}$/,
    // /^(?=^.{3,255}$)([a-zA-Z0-9]+(-[a-zA-Z0-9]+)?\.)+[a-z]{2,11}$/,
    /^(?=^.{3,255}$)([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-zA-Z]{2,11}$/, //可以校验带-的域名
  ///^(?=^.{3,255}$)((?!.*--)[a-zA-Z0-9]([a-zA-Z0-9-]{0,55}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,11}(?<!-)$/
  // 域名（可校验端口号）
  domainAndPort:
    /^(?=^.{3,255})([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-z]{2,11}(:([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$/,
  //ipv4和域名
  ipv4OrDomain:
    /^(?:(?:(?:1?[1-9]?\d|[1-2][0-4]\d|25[0-5])\.){3}(?:1?[1-9]?\d|[1-2][0-4]\d|25[0-5]))|(?=^.{3,255}$)([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*\.)+[a-zA-Z]{2,11}$/,
  // url地址
  url: /^http(s)?:\/\/(((([a-zA-Z\d]+-?)+(?<!-)\.)+[a-z]{2,11})|(localhost)|((1?[1-9]?\d|[1-2][0-4]\d|25[0-5])\.){3}(1?[1-9]?\d|[1-2][0-4]\d|25[0-5]))(:([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?(\/\S*)?$/,
  //url具体到文件名
  urlWithFileName:
    /^http(s)?:\/\/(((([a-zA-Z\d]+-?)+(?<!-)\.)+[a-z]{2,11})|((1?[1-9]?\d|[1-2][0-4]\d|25[0-5])\.){3}(1?[1-9]?\d|[1-2][0-4]\d|25[0-5]))(:([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?(\/\S*)?$/,
  //url具体到文件类型 (\/\S*\.[a-zA-Z]{2,})?$/ ?代表是否需要必填文件类型
  urlWithFileType:
    /^http(s)?:\/\/(((([a-zA-Z\d]+-?)+(?<!-)\.)+[a-z]{2,11})|((1?[1-9]?\d|[1-2][0-4]\d|25[0-5])\.){3}(1?[1-9]?\d|[1-2][0-4]\d|25[0-5]))(:([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?((\/\S*\.[a-zA-Z]{2,}|\/.\/*))?$/,
  // http https 可选 url具体到文件类型 (\/\S*\.[a-zA-Z]{2,})?$/ ?代表是否需要必填文件类型
  optionalProtocolUrlWithFileType:
    /^(?:http(s)?:\/\/)?([a-zA-Z\d-]+\.)+[a-zA-Z]{2,11}(\/[^\s]*)?(\.[a-zA-Z]{2,4})?$/,
  // http https 必填 url具体到文件类型 (\/\S*\.[a-zA-Z]{2,})?$/ ?代表是否需要必填文件类型
  protocolUrlWithFileType:
    /^(?:http(s)?:\/\/)([a-zA-Z\d-]+\.)+[a-zA-Z]{2,11}(\/[^\s]*)?(\.[a-zA-Z]{2,4})?$/,
  // 无协议url地址 端口号可选 有路径
  noProtocolUrl:
    /^([\w-]+\.)+[\w-]+(:([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?(\/\S*)?$/,
  // 无协议url地址 无路径 端口号可选
  noProtocolNoEndWithStrUrl:
    /^([\w-]+\.)*[\w-]+(:([1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?$/,
  // 无端口号url地址
  noPortUrl: /^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/\S*)?$/,
  // 无协议无端口号url地址
  noProtocolAndPortUrl: /^([\w-]+\.)+[\w-]+(\/\S*)?$/,
  //校验金额
  balance: /^(?!0\d)\d{1,5}(?:\.\d{1,2})?$/,
  // 邮箱
  // email: /^(?=^.{6,50}$)\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/,
  email:
    /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
  qq: /^[1-9][0-9]{4,11}$/,
  phone:
    /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/,
  // Telegram
  telegram: /^https:\/\/t\.me\/[a-zA-Z0-9]{1,88}$/,
  // Skype
  skype: /^https:\/\/join\.skype\.com\/invite\/[A-Za-z0-9]{1,100}$/,
  cname: /^(?!-)(?!.*--)[a-zA-Z0-9-]{6,20}(?<!-)$/
}

// 验证端口号
export const validateSitePort: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  callback(
    validateHandler(value, (data) => {
      const port = Number(data)
      if (isNaN(port)) {
        return '端口号格式错误'
      }
      if (port < 1 || port > 65535) {
        return '端口范围：1~65535'
      }
    })
  )
}

// 验证IPv4地址
export const validateIpv4: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  callback(
    validateHandler(value, (data) =>
      regExpValidateHandler(data, regexpMap.ipv4, 'IP地址格式错误')
    )
  )
}

// 验证IPv6地址
export const validateIpv6: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  callback(
    validateHandler(value, (data) =>
      regExpValidateHandler(data, regexpMap.ipv4, 'IP地址格式错误')
    )
  )
}

// 验证域名
export const validateDomain: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  callback(
    validateHandler(value, (data) =>
      regExpValidateHandler(data, regexpMap.domain, '域名格式错误')
    )
  )
}

// 验证域名，可携带端口号
export const validateDomainAndPort: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  callback(
    validateHandler(value, (data) =>
      regExpValidateHandler(
        data,
        regexpMap.domainAndPort,
        data.includes(':') ? '域名格式错误，端口范围为1~65535' : '域名格式错误'
      )
    )
  )
}

// 验证泛域名，包括正常域名
export const validatePanDomain: FormValidator = (value: any, callback) => {
  callback(
    validateHandler(value, (data) => {
      const error = '域名格式错误'
      if (data.startsWith('*.')) {
        data = data.substring(2, data.length - 1)
      }
      return regExpValidateHandler(data, regexpMap.domain, error)
    })
  )
}

// 验证主控地址
export const validateMgrAddr: FormValidator = (
  value: string,
  callback: (error?: string) => void
) => {
  const ipv4 = regexpMap.ipv4
  const ipv6 = regexpMap.ipv6
  const ipv4AndPort = regexpMap.ipv4AndPort
  const ipv6AndPort = regexpMap.ipv6AndPort
  const domain = regexpMap.domain
  const domainAndPort = regexpMap.domainAndPort
  if (!value) {
    return callback('请输入管理端地址')
  }
  if (!value.startsWith('http://') && !value.startsWith('https://')) {
    return callback('管理端地址错误')
  }
  const index = value.indexOf('://')
  const host = value.substring(index + 3).toString()

  if (
    ipv4.test(host) ||
    ipv6.test(host) ||
    ipv4AndPort.test(host) ||
    ipv6AndPort.test(host) ||
    domain.test(host) ||
    domainAndPort.test(host)
  ) {
    return callback()
  } else {
    return callback('管理端地址错误')
  }
}

// 验证主控地址
export const validateMasterAddr: FormValidator = (
  value: string,
  callback: (error?: string) => void
) => {
  const ipv4 = regexpMap.ipv4
  const ipv6 = regexpMap.ipv6
  const ipv4AndPort = regexpMap.ipv4AndPort
  const ipv6AndPort = regexpMap.ipv6AndPort
  const domain = regexpMap.domain
  const domainAndPort = regexpMap.domainAndPort
  if (!value) {
    return callback('请输主控通信地址')
  }
  if (value && value.length > 255) {
    return callback('输入已达上限（255字符），请重新输入')
  }
  if (!value.startsWith('http://') && !value.startsWith('https://')) {
    return callback('主控通信地址错误')
  }
  const index = value.indexOf('://')
  const host = value.substring(index + 3).toString()

  if (
    ipv4.test(host) ||
    ipv6.test(host) ||
    ipv4AndPort.test(host) ||
    ipv6AndPort.test(host) ||
    domain.test(host) ||
    domainAndPort.test(host)
  ) {
    return callback()
  } else {
    return callback('主控通信地址错误')
  }
}

// 验证文件后缀
export const validateSuffix: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  // const reg = /^[A-Za-z0-9*-,/]+$/
  const reg = /^([A-Za-z0-9*-/]+(,[A-Za-z0-9*-/]+)*)?$/
  callback(
    validateHandler(value, (data) => {
      if (data.indexOf('.') !== -1)
        return callback('格式错误,请检查后缀是否正确')
      if (data.startsWith(',') || data.endsWith(','))
        return callback('请输入文件后缀，多个值用英文逗号隔开，区分大小写')
      return regExpValidateHandler(
        data,
        reg,
        '请输入文件后缀，多个值用英文逗号隔开，区分大小写'
      )
    })
  )
}

// 验证账号
export const validateAccount: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  const reg = /^[0-9A-Za-z_]{4,18}$/
  callback(
    validateHandler(value, (data) =>
      regExpValidateHandler(
        data,
        reg,
        '请输入4-18个字符，可包含英文字母、数字、下划线'
      )
    )
  )
}

/**密码验证 */
export const validatePassword = (
  value: string,
  callback: (error?: string) => void
) => {
  // 完整正则
  //  const reg =
  //   /^(?=[\w()`!@#$%^&*\-+=|{}[\]:;'<>,.?]*\d)(?=[\w()`!@#$%^&*\-+=|{}[\]:;'<>,.?]*[()`!@#$%^&*_\-+=|{}[\]:;'<>,.?])(?=[\w()`!@#$%^&*\-+=|{}[\]:;'<>,.?]*[a-z])(?=[\w()`!@#$%^&*\-+=|{}[\]:;'<>,.?]*[A-Z])([\w()`!@#$%^&*\-+=|{}[\]:;'<>,.?]){8,20}$/
  const reg1 = /[_()`~!@#$%^&*\-+=|{}[\]:;'<>,.?]/ // 包含特殊字符（除空格）
  const reg2 = /[\d]/ // 包含数字
  const reg3 = /[a-z]/ // 包含小写
  const reg4 = /[A-Z]/ // 包含大写
  const error =
    '请输入8-20个字符，需包含大小写英文字母、数字和标点符号（除空格）'
  if (!value) {
    return callback('请输入密码')
  }
  if (!value.match(reg1)) {
    return callback(error)
  }
  if (!value.match(reg2)) {
    return callback(error)
  }
  if (!value.match(reg3)) {
    return callback(error)
  }
  if (!value.match(reg4)) {
    return callback(error)
  }
  if (value.length < 8 || value.length > 20) {
    return callback(error)
  }
  return callback()
}

// 验证 验证码
export const validateVerifyCode: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  const reg = /^\d{6}$/
  callback(
    validateHandler(value, (data) =>
      regExpValidateHandler(data, reg, '请输入6位数字验证码')
    )
  )
}

// 验证URL地址
export const validateURL: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  callback(
    validateHandler(value, (data) => {
      if (data.length > 2048) {
        return '长度不可超过2048位字符'
      }
      const errMsg = regExpValidateHandler(
        data,
        regexpMap.url,
        '请输入格式正确并带有协议的URL'
      )
      if (errMsg) {
        return errMsg
      }
      const u = new URL(data)
      if (u.hostname.length > 63) {
        return '域名长度不可超过63位'
      }
    })
  )
}

// 验证URL路径
export const validateUrlPath: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  callback(
    validateHandler(value, (data) => {
      if (data.length > 2048) {
        return '长度不可超过2048位字符'
      }
      if (!data.startsWith('/') || data.includes('?')) {
        return '路径配置必须以/开头，不支持携带参数'
      }
    })
  )
}

// 验证URL查询参数
export const validateUrlQueryString: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  const reg = /^(([a-zA-Z_][\w]*)+=\S*&?)+$/
  callback(
    validateHandler(value, (data) => {
      if (data.length > 2048) {
        return '长度不可超过2048位字符'
      }
      return regExpValidateHandler(data, reg, 'URL查询字符串格式错误')
    })
  )
}

// 验证标题
export const validateTitle: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  const reg = /^[a-zA-Z0-9\u4E00-\u9FA5]{1,30}$/
  callback(
    validateHandler(value, (data) => {
      if (data.length > 30) {
        return '标题长度为30位以内的字母，数字和汉字'
      }
      return regExpValidateHandler(
        data,
        reg,
        '标题为长度30位以内的汉字，字母和数字'
      )
    })
  )
}

// 验证cname
export const validateCName: FormValidator = (
  value: number | string | string[] | number[],
  callback: (error?: string) => void
) => {
  callback(
    validateHandler(value, (data) =>
      regExpValidateHandler(
        data,
        regexpMap.cname,
        '请输入6 ~ 20 位字母和数字或-'
      )
    )
  )
}

export async function validateRuleID(value: string) {
  const reg = /[^\d]/g
  if (reg.test(value)) {
    return Promise.resolve(false)
  }
  return Promise.resolve(true)
}
